/*
 * This file is part of aion-emu <aion-emu.com>.
 *
 *  aion-emu is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  aion-emu is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with aion-emu.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.aionengine.gameserver.dataholders;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.HiddenFileFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;

/**
 * This class is responsible for loading data from static .txt files.<br>
 * It's used as base class of {@link NpcData} and {@link SpawnData}.<br>
 * <br>
 * <font color="red">NOTICE: </font> This class is used temporarily and later will be removed and npc and spawn data
 * will be loaded with xml loader.<br>
 * <br>
 * <font color="red"><b>Do not use this class for anything else than <tt>NpcData</tt> or <tt>SpawnData</tt></b></font>
 *
 * @author Luno
 */
abstract class DataLoader {

    /**
     * The logger used for <tt>DataLoader</tt> and its subclasses
     */
    protected Logger log = LoggerFactory.getLogger(getClass().getName());

    /**
     * Relative path to directory containing .txt files with static data
     */
    private static final String PATH = "./data/static_data/";

    /**
     * File containing data to load ( may be file or directory )
     */
    private File dataFile;

    /**
     * Constructor that is supposed to be called from subclass.
     *
     * @param file file or directory in the static data directory, containing data that will be loaded
     */
    DataLoader(String file) {
        this.dataFile = new File(PATH + file);
    }

    /**
     * This method is supposed to be called from subclass to initialize data loading process.<br>
     * <br>
     * This method is using file given in the constructor to load the data and there are two possibilities:
     * <ul>
     * <li>Given file is file is in deed the <b>file</b> then it's forwarded to {@link #loadFile(File)} method</li>
     * <li>Given file is a <b>directory</b>, then this method is obtaining list of all visible .txt files in this
     * directory and subdirectiores ( except hidden ones and those named "new" ) and call {@link #loadFile(File)} for each
     * of these files.
     * </ul>
     */
    @SuppressWarnings("deprecation")
	protected void loadData() {
        if (dataFile.isDirectory()) {
            Collection<?> files = FileUtils.listFiles(
                    dataFile,
                    FileFilterUtils.andFileFilter(FileFilterUtils.andFileFilter(
                            FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter("new")),
                            FileFilterUtils.suffixFileFilter(".txt")), HiddenFileFilter.VISIBLE), HiddenFileFilter.VISIBLE);

            for (Object file1 : files) {
                File f = (File) file1;
                loadFile(f);
            }
        } else {
            loadFile(dataFile);
        }
    }

    /**
     * This method is loading data from particular .txt file.
     *
     * @param file a file which the data is loaded from.<br>
     *             The method is loading the file row by row, omitting those started with "#" sign.<br>
     *             Every read row is then forwarded to {@link #parse(String)} method, which should be overriden in subclcass.
     */
    private void loadFile(File file) {
        LineIterator it = null;
        try {
            it = FileUtils.lineIterator(file);
            while (it.hasNext()) {
                String line = it.nextLine();
                if (line.isEmpty() || line.startsWith("#")) {
                    continue;
                }
                parse(line);
            }
        } catch (IOException e) {
            log.error("Error while loading " + getClass().getSimpleName() + ", file: " + file.getPath(), e);
        } finally {
            LineIterator.closeQuietly(it);
        }
    }

    /**
     * This method must be overriden in every subclass and is responsible for parsing given <tt>dataEntry</tt> String
     * which represents one row from data file.
     *
     * @param dataEntry A String containing data about a data entry, that is to be parsed by this method.
     */
    protected abstract void parse(String dataEntry);

    /**
     * Saves data to the file. Used only by {@link SpawnData}.
     *
     * @return true if the data was successfully saved, false - if some error occurred.
     */
    public boolean saveData() {
        String desc = PATH + getSaveFile();

        log.info("Saving " + desc);

        FileWriter fr = null;
        try {
            fr = new FileWriter(desc);

            saveEntries(fr);

            fr.flush();

            return true;
        } catch (Exception e) {
            log.error("Error while saving " + desc, e);
            return false;
        } finally {
            if (fr != null) {
                try {
                    fr.close();
                } catch (Exception e) {
                    log.error("Error while closing save data file", e);
                }
            }
        }
    }

    /**
     * Name of the file which is used to store data in.<br>
     * This method must be overriden in sublass if we want to be able to store its data. It's used only in
     * {@link SpawnData} and should not be used anywhere else.
     *
     * @return name of the file
     */
    protected abstract String getSaveFile();

    /**
     * This method must be overriden in subclass which we want to be able to save data. It's responsibility is basicly to
     * put data into given FileWriter instance.
     *
     * @param fileWriter
     * @throws Exception
     */
    protected void saveEntries(FileWriter fileWriter) throws Exception {
        // TODO Auto-generated method stub

    }
}
